package com.nexgo.lamp;

import com.nexgo.oaf.apiv3.device.led.LEDDriver;
import com.nexgo.oaf.apiv3.device.led.LightModeEnum;
import com.nexgo.payment.api.ApiDeviceEngine;

import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.observers.DisposableObserver;

/**
 * Created by xiaox on 2017/11/29.
 */

public class LampManager {
    private OperateType blueLamp;
    private OperateType yellowLamp;
    private OperateType greenLamp;
    private OperateType redLamp;
    private long period;
    private final LEDDriver mSdkLedDriver;
    private final CompositeDisposable mDisposables;

    private LampManager() {
        mSdkLedDriver = ApiDeviceEngine.getInstance().getLEDDriver();
        mDisposables = new CompositeDisposable();
    }

    public void operate() {
        operate(blueLamp, LightModeEnum.BLUE);
        operate(yellowLamp, LightModeEnum.YELLOW);
        operate(greenLamp, LightModeEnum.GREEN);
        operate(redLamp, LightModeEnum.RED);
    }

    private void operate(OperateType type, LightModeEnum color) {
        if (type != null) {
            switch (type) {
                case ON:
                case OFF:
                    mSdkLedDriver.setLed(color, OperateType.ON.equals(type));
                    if (period != 0) {
                        Observable<Long> interval = Observable.interval(period, TimeUnit.MILLISECONDS);
                        addDisposable(interval.subscribe(aLong -> close()));
                    }
                    break;
                case TWINK_CONNECTING:
                case TWINK_IDLE:
                    Observable<Long> interval = Observable.interval(1, TimeUnit.MILLISECONDS);
                    interval.take(period);
                    addDisposable(interval.subscribeWith(new LampObserver(type.onPeriod, type.offPeriod, color)));
                    break;
                default:
                    break;
            }
        }
    }

    public void close() {
        mDisposables.dispose();
        mSdkLedDriver.setLed(LightModeEnum.BLUE, false);
        mSdkLedDriver.setLed(LightModeEnum.YELLOW, false);
        mSdkLedDriver.setLed(LightModeEnum.GREEN, false);
        mSdkLedDriver.setLed(LightModeEnum.RED, false);
    }

    private void addDisposable(Disposable disposable) {
        mDisposables.add(disposable);
    }

    private class LampObserver extends DisposableObserver<Long> {
        private final int mOnPeriod;
        private final int mOffPeriod;
        private final LightModeEnum mColor;
        private boolean mIsOn;

        LampObserver(int onPeriod, int offPeriod, LightModeEnum color) {
            mOnPeriod = onPeriod;
            mOffPeriod = offPeriod;
            mColor = color;
        }

        @Override
        public void onNext(Long aLong) {
            long l = aLong % (mOnPeriod + mOffPeriod);
            if (l < mOnPeriod) {
                if (!mIsOn) {
                    mIsOn = true;
                    mSdkLedDriver.setLed(mColor, true);
                }
            } else {
                if (mIsOn) {
                    mIsOn = false;
                    mSdkLedDriver.setLed(mColor, false);
                }
            }

        }

        @Override
        public void onError(Throwable e) {
            close();
        }

        @Override
        public void onComplete() {
            close();
        }
    }

    public static class Builder {
        private OperateType blueLamp;
        private OperateType yellowLamp;
        private OperateType greenLamp;
        private OperateType redLamp;
        private long period;

        Builder setBlueLamp(OperateType blueLamp) {
            this.blueLamp = blueLamp;
            return this;
        }

        Builder setYellowLamp(OperateType yellowLamp) {
            this.yellowLamp = yellowLamp;
            return this;
        }

        Builder setGreenLamp(OperateType greenLamp) {
            this.greenLamp = greenLamp;
            return this;
        }

        Builder setRedLamp(OperateType redLamp) {
            this.redLamp = redLamp;
            return this;
        }

        Builder setPeriod(long period) {
            this.period = period;
            return this;
        }

        public LampManager build() {
            LampManager lampManager = new LampManager();
            lampManager.blueLamp = blueLamp;
            lampManager.yellowLamp = yellowLamp;
            lampManager.greenLamp = greenLamp;
            lampManager.redLamp = redLamp;
            lampManager.period = period;
            return lampManager;
        }
    }

    /**
     * 灯操作类型
     */
    public enum OperateType {
        /**
         * 开
         */
        ON(0, 0),
        /**
         * 关
         */
        OFF(0, 0),
        /**
         * 连接闪烁
         */
        TWINK_CONNECTING(500, 500),
        /**
         * 空闲闪烁
         */
        TWINK_IDLE(200, 4800);

        private final int onPeriod;
        private final int offPeriod;

        OperateType(int onPeriod, int offPeriod) {
            this.onPeriod = onPeriod;
            this.offPeriod = offPeriod;
        }
    }
}
